package ru.gelin.android.bells.timers;

import java.util.Calendar;
import java.util.Date;

/**
 *  Timer.
 */
public class Timer {

    /** ID of the timer in the collection */
    int id;
    
    /** Is this timer enabled? */
    boolean enabled = true;
    
    /** Start time */
    Date start = new Date();
    
    /** Period */
    Period period = new Period(0, 30);
    
    /** Timer message to display */
    String message = "";
    
    /** Timer alarm type */
    String alarm;

    public Timer() {
    }
    
    /**
     *  Creates timer with specified ID.
     */
    Timer(int id) {
        this.id = id;
    }
    
    /**
     *  Returns the ID of the timer. 
     *  ID is meaningful only inside the collection of timers.
     *  @return
     */
    public int getId() {
        return id;
    }
    /**
     *  Sets the ID of the timer.
     */
    void setId(int id) {
        this.id = id;
    }

    /**
     *  Returns true if this timer is enabled.
     */
    public boolean isEnabled() {
        return enabled;
    }
    /**
     *  Sets enabled flag for the timer.
     */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
     *  Returns the timer message to display to the user.
     */
    public String getMessage() {
        return message;
    }
    /**
     *  Sets the timer message to display to the user.
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     *  Returns the alarm type.
     */
    public String getAlarm() {
        return alarm;
    }
    /**
     *  Sets the alarm type.
     */
    public void setAlarm(String alarm) {
        this.alarm = alarm;
    }

    /**
     *  Gets the start time of the timer.
     *  Each time the alarm happens the start time is shifted to
     *  period.
     */
    public Date getStartTime() {
        return start;
    }
    /**
     *  Sets the start time of the timer.
     */
    public void setStartTime(Date start) {
        this.start = normalizeDate(start);
    }

    /**
     *  Gets the period of the timer.
     */
    public Period getPeriod() {
        return period;
    }
    /**
     *  Sets the period for the timer.
     */
    public void setPeriod(int hours, int minutes) {
        this.period = new Period(hours, minutes);
    }

    /**
     *  Returns the alarm time.
     *  It time in the future when the timer should alarm.
     *  @param  now current time
     *  @return some time in future
     */
    public Date getAlarmTime(Date now) {
        Date nowMinute = normalizeDate(now);
        Date result = start;
        while (!result.after(nowMinute)) {
            result = period.add(result);
        }
        return result;
    }
    
    /**
     *  Normalizes the timer, i.e. start time is set to not more than one period
     *  in the past or now or in the future.
     *  @param  now time relative to which normalize the timer
     */
    public void normalize(Date now) {
        Date nowMinute = normalizeDate(now);
        if (!start.before(nowMinute)) {
            return;     //start is now or in the future
        }
        start = period.sub(getAlarmTime(now));
    }
    
    /**
     *  Normalizes dates, i.e. sets seconds and milliseconds to zero.
     */
    public static Date normalizeDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        if (id > 0) {
            return result;  //just hash code of id
        }
        result = prime * result
                + ((start == null) ? 0 : start.hashCode());
        result = prime * result
                + ((period == null) ? 0 : period.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Timer other = (Timer) obj;
        if (id != other.id)
            return false;
        if (id > 0 && id == other.id) {
            return true;   //equals by ID
        }
        if (start == null) {
            if (other.start != null)
                return false;
        } else if (!start.equals(other.start))
            return false;
        if (period == null) {
            if (other.period != null)
                return false;
        } else if (!period.equals(other.period))
            return false;
        return true;
    }
    
    /**
     *  Prints main properties of the timer.
     */
    public String toString() {
        return "Timer: id = " + id;
    }
    
    /**
     *  Creates new timer equals to this.
     */
    public Timer copy() {
        Timer result = new Timer();
        result.id = id;
        result.enabled = enabled;
        result.start = start;
        result.period = period;
        result.message = message;
        result.alarm = alarm;
        return result;
    }

}
